<?php
// +----------------------------------------------------------------------
// | zlserver [ 小程序 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2018 http://www.zhongliansoft.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: tony <tanyu@zhongliansoft.com>
// +----------------------------------------------------------------------
namespace app\job\import;

use think\exception\ErrorException;
use think\facade\Validate;
use think\queue\Job;
use app\common\model\StudentInfo as StudentInfoModel; 
use app\common\model\User as UserModel; 
use app\common\model\Config as ConfigModel;
use app\common\model\StudentType as StudentTypeModel;
use app\common\model\StudentTypeRel as StudentTypeRelModel;
use app\common\model\StudentTypeParams as StudentTypeParamsModel;
use app\common\model\StudentTypeRelImport as StudentTypeRelImportModel; 
use app\common\model\BookExtraDraw as BookExtraDrawModel;

use app\common\model\Ietask;
use think\facade\Log;

class StudentType
{
    protected $rule = [
        'xh' => 'require|max:40',
        'xm' => 'require|max:40',
        'plan_year' => 'require',
        'plan_season' => 'require',
        'type' => 'require',
        'param' => 'require',
    ];
    protected $msg = [
        'xh.require' => '学号必填',
        'xh.max' => '学号最长40个字符',
        'xm.require' => '姓名必填',
        'xm.max' => '姓名最长40个字符',
        'plan_year.require' => '年度必填',
        'plan_season.require' => '季度必填',
        'type.require' => '类型必填',
        'param.require' => '参数必填',
    ];

    // 数据校验
    public function check($fileId, $filePath)
    {
        $re = [
            'count' => 0,
            'code' => 0,
            'msg' => ''
        ];

        $studentInfoModel = new StudentInfoModel();
        $configModel = new ConfigModel();
        $studentTypeRelImportModel = new StudentTypeRelImportModel();
        $studentTypeModel = new StudentTypeModel();
        $studentTypeParamsModel = new StudentTypeParamsModel();
        $studentTypeRelModel = new StudentTypeRelModel();
        $userModel = new UserModel();
        $data = [];
        $errorData = [];
        try {
            $resXls=import_excel($filePath);  

            if ($resXls['status']) {
                // 清理导入提示
                unset($resXls['data'][0]);
                // 取表头
                $header = $resXls['data'][1];
                unset($resXls['data'][1]);
                $title = $studentTypeRelImportModel->csvHeader();
                $fields = [];

                // 遍历表头
                $last_index = 0;
                foreach ($title as $key => $val) {
                    // 从导入的数据表中查找字段位置
                    $index = array_search($val['desc'], $header);
                    if ($index !== false) {
                        $fields[] = [
                            'index' => $index,
                            'value' => $val['id']
                        ];
                    }
                    $last_index = $index;
                }
 
                if(count($fields) != 6) { 
                    $re['msg']  = '文件格式错误！请先下载导入模板，按模板要求准备导入数据后再次导入！';
                    $re['code']  = -1;
                    return $re;
                } else {

                    // 数据填充
                    $iData = [];
                    if ($fields) {
                        $i = 0;
                        foreach ($resXls['data'] as $key => $val) {
                            foreach ($fields as $fkey => $fval) {
                                $iData[$i][$fval['value']] = $val[$fval['index']];
                                if(is_object($iData[$i][$fval['value']])) {
                                    $iData[$i][$fval['value']] = $iData[$i][$fval['value']]->__toString();
                                }
                            }
                            $i++;
                        }
                    }
    
                    // 增加描述字段
                    $fields[] = [
                        'index' => $last_index + 1,
                        'value' => 'desc'
                    ];
                    
                    $count = count($iData);
                    $errCount = 0;
     
                    // 学号是否存在
                    $xhList = $studentInfoModel->getXhList(); 
                    // 学号姓名是否存在
                    $xhNameList = $studentInfoModel->getXhNameList(); 
                    
                    // 年度，季度
                    $year = $configModel->getYear();
                    $season = $configModel->getSeason()==1?'春季':'秋季';

                    // 判断本次是否修改了类型
                    $bookExtraDrawModel = new BookExtraDrawModel(); 
                    $typeList = $bookExtraDrawModel->field('b.xh, c.name as typeName, a.param_id, d.name as paramName')
                    ->alias('a')
                    ->join('zl_book_extra_draw_detail b', 'a.id = b.draw_id')
                    ->join('zl_student_type c', 'a.type_id = c.id')
                    ->join('zl_student_type_params d', 'a.param_id = d.id')
                    ->where(['a.year' => $year, 'a.season' => $configModel->getSeason()])
                    ->select();

                    // 类型参数列表
                    $xhTypes = [];
                    foreach ($typeList as $typeVal) {
                        $xhTypes[$typeVal['xh'] . '-' . $typeVal['typeName']] = $typeVal['paramName'];
                    }

                    // 类型参数列表
                    $typeList = $studentTypeModel->select();
                    $types = [];
                    foreach ($typeList as $typeVal) {
                        $paramList = $studentTypeParamsModel->where(['type_id'=>$typeVal['id']])->select();
                        foreach ($paramList as $paramVal) {
                            $types[] = $typeVal['name'] . '-' . $paramVal['name'];
                        } 
                    } 

                    $tmp_arr = array(); 
                    // 数据预处理 
                    foreach ($iData as $key => $val) {
                        $errFind = false;
                        //校验数据
                        $validate = new \think\Validate($this->rule, $this->msg);
                        $validate->batch(true);

                        // 数据预处理
                        $time = time();
                        $studentType['xh'] = trim($val['xh']);
                        $studentType['xm'] = trim($val['xm']);
                        $studentType['plan_year'] = trim($val['plan_year']);
                        $studentType['plan_season'] = trim($val['plan_season']);
                        $studentType['type'] = trim($val['type']);
                        $studentType['param'] = trim($val['param']);
                        $studentType['desc'] = '';
                        $studentType['error'] = 0;
 
                        if (!$validate->check($studentType)) {
                            $studentType['error'] = 1;
                            $errCount = $errCount + 1;
                            $errFind = true;

                            $index = 0;
                            foreach ($validate->getError() as $errKey => $value) {
                                if($index == 0) {
                                    $studentType['desc']  = $studentType['desc'] . $value;
                                } else {
                                    $studentType['desc']  = $studentType['desc'] . ';' . $value;
                                }
                                $index++;
                            }  
                        }

                        // 年度
                        if($studentType['plan_year'] != $year){
                            $studentType['error'] = 1;
                            if(strpos($studentType['desc'], '年度') === false) { 
                                if($errFind) {
                                    $studentType['desc'] =  $studentType['desc'] . ';' . $studentType['plan_year'] . '非当前年度';
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $studentType['desc'] =  $studentType['bmmc'] . '非当前年度';
                                }
                            }
                        }

                        // 季度
                        if($studentType['plan_season'] != $season){
                            $studentType['error'] = 1;
                            if(strpos($studentType['desc'], '季度') === false) { 
                                if($errFind) {
                                    $studentType['desc'] =  $studentType['desc'] . ';' . $studentType['plan_season'] . '非当前季度';
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $studentType['desc'] =  $studentType['bmmc'] . '非当前季度';
                                }
                            }
                        }

                        // 判断学号是否存在
                        if (!in_array($studentType['xh'], $xhList)) {
                            $studentType['error'] = 1;

                            if(strpos($studentType['desc'], '学号') === false) { 
                                if($errFind) {
                                    $studentType['desc'] =  $studentType['desc'] . ';' . $studentType['xh'] . '学号不存在';
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $studentType['desc'] =  $studentType['xh'] . '学号不存在';
                                }
                            }
                        } else {
                            // 学号姓名是否一致
                            if (!in_array($studentType['xh'].$studentType['xm'], $xhNameList)) {
                                $studentType['error'] = 1;

                                if($errFind) {
                                    $studentType['desc'] =  $studentType['desc'] . ';' . $studentType['xh'] . '学号姓名不一致！';
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $studentType['desc'] =  $studentType['xh'] . '学号姓名不一致！';
                                }
                            }
                        }
   
                        $type_param_key = $studentType['type'] . '-' . $studentType['param'];
                        // 判断类型是否有效
                        if (!in_array($type_param_key, $types)) {
                            $studentType['error'] = 1;
                             
                            if($type_param_key == '-') { $type_param_key = ''; }
                            if($errFind) {
                                $studentType['desc'] =  $studentType['desc'] . ';' . $type_param_key . '类型参数不存在';
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                $studentType['desc'] =  $type_param_key . '类型参数不存在';
                            } 
                        }

                        // 判断是否已经发书
                        $xh_type_key = $studentType['xh'] . '-' . $studentType['type'];
                        if (array_key_exists($xh_type_key, $xhTypes) && $xhTypes[$xh_type_key] != $studentType['param']) {
                            $studentType['error'] = 1;
                             
                            if($errFind) {
                                $studentType['desc'] =  $studentType['desc'] . ';' . $type_param_key . '该类型参数对应的教材已经发放，不允许修改';
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                $studentType['desc'] =  $type_param_key . '该类型参数对应的教材已经发放，不允许修改';
                            } 
                        }

                        $keyvalue = $studentType['xh'].$studentType['xm'].$studentType['plan_year'].$studentType['plan_season'].$studentType['type'].$studentType['param'];
                        // 自身检测
                        if (in_array($keyvalue, $tmp_arr)) { //搜索$v[$key]是否在$tmp_arr数组中存在，若存在返回true
                            $studentType['error'] = 1;
                            if($errFind) {
                                $studentType['desc'] = $studentType['desc'] . ';' . '导入数据中记录重复'; 
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                $studentType['desc'] = $studentType['desc'] . '导入数据中记录重复'; 
                            }
                        } else { 
                            $tmp_arr[] = $keyvalue; 
                        }

                        if ($studentType['error'] == 1) {
                            $errorData[$errCount - 1] = $studentType;
                        }
    
                        $data[$key] = $studentType;
                        unset($studentType);
                    }
                } 
            } else {
                $re['msg']  = $resXls['msg'];
                $re['code']  = -1;
                return $re;
            }
        } catch (Exception $e) {
            $re['msg']  = $e->getMessage();
            $re['code']  = -1;
            return $re;
        }

        $re['count'] = $count;
        $re['errCount'] = $errCount;
        $re['data'] = json_encode($data);
        $re['fileId'] = $fileId;
        $re['filePath'] = $filePath;
        $re['errData'] = json_encode($errorData);
        return $re;
    }

    //执行导入任务
    public function exec(Job $job, $params)
    { 
        $ietaskModle = new Ietask();

        $ietaskInfo = $ietaskModle->where(['id' => $params['task_id']])->find();
 
        $studentTypeRelImportModel = new StudentTypeRelImportModel();
        $userModel = new UserModel();
        $message = [];
        $count = 0;         // 记录总数
        $progress = 0;
        try {
            $file = json_decode($params['params'], true);
            $resXls=import_excel($file['file_path']); 
            $count = count($resXls['data'])-2;

            if ($resXls['status']) {
                // 清理导入提示
                unset($resXls['data'][0]);
                // 取表头
                $header = $resXls['data'][1];
                unset($resXls['data'][1]);
                $title = $studentTypeRelImportModel->csvHeader();
                 
                $fields = []; 
                foreach ($title as $key => $val) {
                    $index = array_search($val['desc'], $header);
                    if ($index >= 0) {
                        $fields[] = [
                            'index' => $index,
                            'value' => $val['id']
                        ];
                    }
                }

                // 提取所有学生信息
                $iData = [];
                if ($fields) {
                    $i = 0;
                    foreach ($resXls['data'] as $key => $val) {
                        foreach ($fields as $fkey => $fval) {
                            $iData[$i][$fval['value']] = $val[$fval['index']];
                            if(is_object($iData[$i][$fval['value']])) {
                                $iData[$i][$fval['value']] = $iData[$i][$fval['value']]->__toString();
                            }
                        }
                        $i++;
                    }
                }

                // 清空临时表
                $studentTypeRelImportModel->where(['manage_id' => $ietaskInfo['manage_id']])->delete();

                // 学生信息写入临时表
                unset($student_comment);
                $student_comment = []; 
                foreach ($iData as $key => $val) {
                    $student_comment[] = [
                        'xh'            => trim($val['xh']),
                        'xm'            => trim($val['xm']),
                        'plan_year'     => trim($val['plan_year']),
                        'plan_season'   => trim($val['plan_season']),
                        'type'          => trim($val['type']),
                        'param'         => trim($val['param']),
                        'manage_id'     => trim($ietaskInfo['manage_id']),
                    ];
     
                    // 每隔100条数据更新一次数据处理进度
                    $progress++; 
                    if($progress %100==0) {
                        // 批量插入数据
                        $studentTypeRelImportModel->startTrans(); 
                        $num = $studentTypeRelImportModel->insertAll($student_comment);
                        if($num != 100) {
                            $studentTypeRelImportModel->rollback();
                            Log::record($student_comment . '用户数据保存失败');
                        } else {                        
                            $studentTypeRelImportModel->commit();
                        }

                        // 清理环境
                        unset($student_comment);
                        $student_comment = [];
                    }
                }

                // 批量插入数据
                $studentTypeRelImportModel->startTrans(); 
                $num = $studentTypeRelImportModel->insertAll($student_comment);               
                $studentTypeRelImportModel->commit(); 

                // 执行存储过程批量更新学生信息
                $studentTypeRelImportModel->query("call programUpdateStudentType('".$ietaskInfo['manage_id']."');");
        
                // 清空临时表
                $studentTypeRelImportModel->where(['manage_id' => $ietaskInfo['manage_id']])->delete();
                
                $uData['status'] = $ietaskModle::IMPORT_SUCCESS_STATUS;
                $uData['message'] = '导入成功';
                if ($message) {
                    $uData['message'] .= json_encode($message);
                }

                $uData['count'] = $count;
                $ietaskModle->update($uData, ['id' => $params['task_id']]);
            } else {
                $uData['status'] = $ietaskModle::IMPORT_FAIL_STATUS;
                $uData['message'] = $resXls['msg'];
                $uData['utime'] = time();
                $ietaskModle->update($uData, ['id' => $params['task_id']]);
            }
        } catch (Exception $e) {
            $message[] = $e->getMessage();
        }
        if ($job->attempts() > 3) {
            $uData['status'] = $ietaskModle::IMPORT_FAIL_STATUS;
            $uData['message'] = '导入执行失败';
            $uData['utime'] = time();
            $ietaskModle->update($uData, ['id' => $params['task_id']]);
            $job->delete();
        }
    }

    public function failed($data)
    {

        // ...任务达到最大重试次数后，失败了
    }
}
